package 课外知识;
/**
 * 对象比较
 * Integer i=new Integer(50);
 * Integer j=new Integer(50);
 * System.out.println(i==j);  //运行的结果是false
 * Integer i=Integer.valueOf(100);
 * Integer j=Integer.valueOf(100);
 * System.out.println(i==j);  //运行的结果是true
 * Integer i=new Integer.valueOf(400);
 * Integer j=new Integer.valueOf(400);
 * System.out.println(i==j);//运行结果是false
 * Integer i=100;
 * Integer j=100;
 * System.out.println(i==j);//运行结果是true
 * 然后再用400这个数试一试，通过实验运行的结果是false，
 *public static Integer valueOf(int i){
 * if(i>=-128&&i<=IntegerCache.high)
 * return IntegerCache.cache[i+128];
 * else return new Integer(i);
 * }
 * 通过看源码能够知道整数类型在-128~127之间时，会使用缓存。
 * 造成的效果就是，如果已经创建了一个相同的整数，
 * 使用valueOf创建第二次时，不会使用new 关键字，
 * 而是用已经缓存的对象。所以使用valueOf方法创建两次对象，
 * 若对应数值相同，且数值在-128~127之间时，两个对象指向同一个地址。
 * 使用Integer i=400这样的方法创建Integer对象与使用valueOf方法的效果是一样的,
 * 若要比较，使用compareTo或者equals方法是更好的
 */
/**
 *    单个 Java 文件长度限制
 *    一般的，一个 Java 类可以写多少行，几乎没人知道，因为没试验过。
 *
 *实际上，Java 对单个类文件时有长度限制的。单个 Java 文件常量个数上限是 65536。
 * 超过这个数字会报：
 * Too many constants, the constant pool for XXX would exceed 65536 entries。
 *
 *这是因为.class文件头 4 个字节的模数（magic number）是小写的
 * 0xca,0xfe,0xba,0xbe。0xCA,0xFE,0xBA,0xBE连起来就是
 * cafebabe，这就是 Class 文件的行数。
 */

/**
 * String 的长度是有限制的。
 * 编译期的限制：字符串的UTF8编码值的字节数不能超过65535，字符串的长度不能超过65534。
 * 运行时限制：字符串的长度不能超过2^31-1，占用的内存数不能超过虚拟机能够提供的最大值。
 * 另外，本文的理论是基于 Java8 的。JDK9 以后对 String 的存储进行了优化。
 * 底层不再使用 char 数组存储字符串，而是使用 byte 数组。
 * 这样对于 LATIN1 字符的字符串可以节省一倍的内存空间。
 */


import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 方法参数不能超过 255 个
 */
public class 奇奇怪怪的知识 {
    public static final String a;
    public static final String b;
    public static final String aa="123";
    public static final String bb="456";
    public static  String aaa="123";
    public static  String bbb="456";

    static {
        a = "123";
        b = "456";
    }

    private static void 字符串连接() {
        String c = "123456";
        String d = a + b;
        System.out.println((c == d)+"\t"+d);//false	123456
//      编译期static不执行的，a和b的值是未知的，static代码块，
//      在初始化的时候被执行，初始化属于类加载的一部分，
//      属于运行期。看看反编译的结果,很明显使用的是indy指令，
//      动态调用返回String类型对象。一个在堆中一个在方法区常量池中，自然是不一样的。

        String e=aa+bb;
        System.out.println((c == e)+"\t"+e);//true	123456
//        对于final类型的常量它们已经在编译中被确定下来，自动执行了+号，把它们拼接了起来，
//        所以就相当于直接”123” + “456”;

        String f=aaa+bbb;
        System.out.println((c == f)+"\t"+f);//false	123456
    }
    public static void main(String[] args) throws Exception {
        Map里存相同元素2();

    }

    private static void Integer比较() {
        //        字符串连接();
        Integer i=125;
        Integer j=125;

        i++;
        j++;
        System.out.println(i==j);
        System.out.println(i==j);
        i++;
        j++;
        System.out.println(i==j);
    }

    //IdentityHashMap  和键是以地址做hash计算
    private static void IdentityHashMapDemo() {
        //        IdentityHashMap();
        IdentityHashMap<String,String> map = new IdentityHashMap<>();
        String s = new String("5".toCharArray());

        String s2 = new String("5".toCharArray());
        map.put(s,"5");
        map.put(s2,"6");
        map.put(new String("1"),"5");
        map.put(new String("1"),"5");
        map.put("1","1");
        map.put("1","1");
        System.out.println(map);
    }

    private static void Map里存相同元素2() throws NoSuchFieldException, InstantiationException, IllegalAccessException {


        Class<HashMap> mapClass = HashMap.class;
        Field threshold = mapClass.getDeclaredField("threshold");
        threshold.setAccessible(true);
        HashMap<List,String> map = mapClass.newInstance();//HashMap的位置时根据  (h = key.hashCode()) ^ (h >>> 16)

        List<List> listList = new ArrayList<>();
//        HashMap<List,String> map=new HashMap<>();
        List list=new ArrayList();
        for (int i = 0; i < 15; i++) {
            list =new ArrayList();
            list.add(1);
            for (int j = 0; j < listList.size(); j++) {
                listList.get(j).add(listList.get(j).size()+1);
            }
            map.put(list,"0");
            listList.add(list);
            System.out.println("在同一个位置添加第"+i+"个 当前map的容量为:"+(Integer)threshold.get(map)/3*4);
        }

        System.out.println("map里有啥");
        System.out.println(map);
        for(List l :listList){
//            System.out.println(l);
            map.remove(l);
        }
        System.out.println("map里全部执行了一遍remove");
        System.out.println(map);


        for (int i = 0; i < listList.size(); i++) {
            while (listList.get(i).size()>1){
                listList.get(i).remove(listList.get(i).size()-1);
            }
        }
        System.out.println("将map里的list的其他删掉");
        System.out.println(map);

        System.out.println((Integer)threshold.get(map)/3*4+"当前map的容量");
//        System.out.println(threshold.get(map)+"modCount");

//        System.out.println(map.threshold);
        System.out.println("*************************");
        for (int i = 0; i < 40; i++) {
            list=Arrays.asList(i+1);
            map.put(list,"0");
        }
        System.out.println((Integer) threshold.get(map)/3*4+"当前map的容量");
//        System.out.println(map);


        int kk=0;
        Set entrySet = map.entrySet();//返回的类型  Set<Map.Entry<K, V>>
        Iterator iterator = entrySet.iterator();
        while (iterator.hasNext()){
            Object obj = iterator.next();
            Map.Entry entry = (Map.Entry) obj;//Map.Entry 内部接口
            kk++;
            System.out.println(entry.getKey()+"\t"+entry.getValue());//内部接口的方法（）
        } //这种遍历方式 速度快 效率高
        System.out.println(kk);
    }

    private static void 交换() {
        int[] l=new int[3];
        jh(l);
        for (int i = 0; i < 3; i++) {
            System.out.println(l[i]);
        }
    }
    private static void jh(int[] list) {
        list[2]=5;
    }

    private static void Map里存相同元素() throws Exception {
        Class<HashMap> mapClass = HashMap.class;
        Field threshold = mapClass.getDeclaredField("threshold");
        threshold.setAccessible(true);
        HashMap<List,String> map = mapClass.newInstance();

//        HashMap<List,String> map=new HashMap<>();
        List list=new ArrayList();
        List list1=new ArrayList();
        list.add(5);

        list1=new ArrayList(list);
        map.put(list,"哈哈list");
        System.out.println(map);//{[5]=哈哈list}
        list.add(116);
        map.put(list,"哈哈哈哈list");
        map.put(list1,"哈哈list1");
        System.out.println(map);//{[5, 116]=哈哈哈哈list, [5, 116]=哈哈list, [5]=哈哈list1}
        list.remove(1);
        System.out.println(map);//{[5]=哈哈哈哈list, [5]=哈哈list, [5]=哈哈list1}//
        map.remove(Arrays.asList(5));
        //map.remove(Arrays.asList(5));会删除一个
        //map.remove(Arrays.asList(5));会删除另一个
        //map.remove(Arrays.asList(5));不会删除三个  因为有一个时根据有集合[5, 116]的hash存进去的

        System.out.println(threshold.get(map)+"           66");

//        System.out.println(map.threshold);
        System.out.println("*************************");
        for (int i = 0; i < 15; i++) {
            list=Arrays.asList(i);
            map.put(list,"0");
        }
        System.out.println(threshold.get(map)+"           66");
//        System.out.println(map);


        Set entrySet = map.entrySet();//返回的类型  Set<Map.Entry<K, V>>
//        System.out.println(entrySet);//[[5, 6]=哈哈, [5, 6]=哈哈]
        Iterator iterator = entrySet.iterator();
        while (iterator.hasNext()){
            Object obj = iterator.next();
            Map.Entry entry = (Map.Entry) obj;//Map.Entry 内部接口
            System.out.println(entry.getKey()+"\t"+entry.getValue());//内部接口的方法（）
        } //这种遍历方式 速度快 效率高
        System.out.println("-------------------------------------");
        for (Map.Entry j :map.entrySet()){

            System.out.println(j.getKey()+"\t"+j.getValue());

        }

    }

    private static void StringBuilderDemo() {
        /**
         * 有一个初始化的java字符串(JDK出娘胎自带的)，
         * 在加载sun.misc.Version这个类的时候进入常量池
         */
        String str1=new StringBuilder("j").append("ava").toString();
        String str11=new StringBuilder("1.8.0_261").append("").toString();
        String a ="j";
        String b ="ava";
        String c=a+b;
        System.out.println(str11 == str11.intern());//false
        System.out.println(c == c.intern());//false  加载sun.misc.Version这个类的时候有些常量进入常量池
        String str2=new StringBuilder("jee").append("ava").toString();
        System.out.println(str2 == str2.intern());//true
    }

    private static void 汉字的字节大小() {
        String s = "你";
        System.out.println(s.getBytes(StandardCharsets.UTF_8).length);//utf-8  3       utf-16  4
        System.out.println(s.codePoints().count());
        System.out.println(s.length());
        System.out.println(s.codePointCount(0, s.length()));
    }

    private static void NaN冷知识() {
        /**
         * 4.如何判断一个数是否是NaN？
         * 答案：使用Double.isNaN(double)或Float.isNaN(float)。其实现是一个数不等于自己，就是NAN：
         *
         * public static boolean isNaN(double v) {
         *     return (v != v);
         * }
         */
        double d1 = Double.NaN;
        double d3 = Double.NaN;//唯一一个  自己不等于自己的
        System.out.println("d3 == d1 : " + (d3 == d1));//d3 == d1 : false
        System.out.println(Double.isNaN(d3));
    }

}
